package jnpf.database.source.impl;

import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import jnpf.base.DbTableModel;
import jnpf.database.data.DataSourceContextHolder;
import jnpf.database.enums.DataTypeEnum;
import jnpf.database.enums.DbAliasEnum;
import jnpf.database.enums.DbSttEnum;
import jnpf.database.source.DbBase;
import jnpf.database.model.DbTableFieldModel;
import jnpf.database.model.dto.DbTableDTO;
import jnpf.database.util.DbUtil;
import jnpf.util.JdbcUtil;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class DbDm extends DbBase {

    @Override
    public void setDbType() {
        dbEncode = "DM";
        driver = "dm.jdbc.driver.DmDriver";
        fieldSql = "select distinct A.column_name AS "+DbAliasEnum.FIELD_NAME.AS()+"," +
                        " A.data_type AS "+DbAliasEnum.DATA_TYPE.AS()+", " +
                        "A.data_length AS "+DbAliasEnum.DATA_LENGTH.AS()+"," +
                        "case A.nullable when 'N' then '1' else '0' end AS "+DbAliasEnum.PRIMARY_KEY.AS()+"," +
                        "case A.nullable when 'N' then '0' else '1' end AS "+DbAliasEnum.ALLOW_NULL.AS()+"," +
                        "B.comments AS "+DbAliasEnum.FIELD_COMMENT.AS()+" from user_tab_columns A " +
                        "left join user_col_comments B on " +
                        "A.table_name=B.table_name and A.column_name=B.column_name " +
                        "where A.table_name = '"+ DbSttEnum.TABLE.getTarget() +"'";
        listSql =   "SELECT " +
                    "a.TABLE_NAME "+DbAliasEnum.TABLE_NAME.AS()+", " +
                    "b.COMMENTS "+DbAliasEnum.TABLE_COMMENT.AS()+
                    "\nFROM " +
                    "user_tables a, " +
                    "user_tab_comments b " +
                    "WHERE " +
                    "a.TABLE_NAME = b.TABLE_NAME " +
                    "and a.TABLESPACE_NAME='"+ DbSttEnum.TABLE_SPACE.getTarget()+"'";
    }

    @Override
    public String getDataType(DataTypeEnum dte){
        return dte.getDmFieldType();
    }

    @Override
    public String getConnectionUrl(String host, String port, String dbName) {
        return "jdbc:dm://" + host + ":" + port + "/" + dbName +
                "?zeroDateTimeBehavior = convertToNull&useUnicode=true&characterEncoding=utf-8";
    }

    @Override
    public void setDynamicMap(HashMap<String, TableNameHandler> map, DbTableModel dbTableModel) {
        map.put(dbTableModel.getTable(), (sql, tableName) -> DataSourceContextHolder.getDatasourceName()+"."+dbTableModel.getTable());
    }

    @Override
    public DbTableModel getTableModel(ResultSet result) throws SQLException {
        return DbUtil.getTableModelCommon(result,
                true,
                true,
                true,
                false,
                false,
                true
        );
    }


    @Override
    public DbTableFieldModel getFieldModel(ResultSet result, Map<String, Object> map) throws SQLException {
        return DbUtil.getFieldModelCommon(result,this,new DbTableFieldModel());
    }

    @Override
    public void createTable(DbTableDTO dto) {
        StringBuilder sql = new StringBuilder();
        sql.append("create table " + dto.getNewTable() + " ");
        sql.append("( ");
        for (DbTableFieldModel item : dto.getDbTableFieldList()) {
            sql.append(item.getField() + " " + item.getDataType());
            if ("VARCHAR".equals(item.getDataType()) || "DECIMAL".equals(item.getDataType())) {
                sql.append("(" + item.getDataLength() + ") ");
            }
            if ("1".equals(String.valueOf(item.getPrimaryKey()))) {
                sql.append(" NOT NULL PRIMARY KEY");
            } else if (item.getAllowNull().compareTo(0) == 0) {
                sql.append(" NOT NULL ");
            } else {
                sql.append(" NULL ");
            }
            sql.append(",");
        }
        sql.deleteCharAt(sql.length() - 1);
        sql.append(")\ntablespace "+  dto.getTableSpace() +";");
        //给表添加说明
        sql.append("COMMENT ON TABLE " + dto.getNewTable() + " IS '" + dto.getTableComment() + "';");
        //给字段添加说明
        for (DbTableFieldModel item : dto.getDbTableFieldList()) {
            sql.append("COMMENT ON COLUMN " + dto.getNewTable() + "." + item.getField() + " IS '" + item.getFieldName() + "';");
        }
        JdbcUtil.custom(dto.getConn(),sql.toString());
    }

    @Override
    public void updateTable(DbTableDTO dto) {
        StringBuilder sql = new StringBuilder();
        sql.append("drop table " + dto.getOldTable()+";");
        sql.append("create table " + dto.getNewTable() + " ");
        sql.append("( ");
        for (DbTableFieldModel item : dto.getDbTableFieldList()) {
            sql.append(item.getField() + " " + item.getDataType());
            if ("varchar".equals(item.getDataType()) || "decimal".equals(item.getDataType())) {
                sql.append("(" + item.getDataLength() + ") ");
            }
            if ("1".equals(String.valueOf(item.getPrimaryKey()))) {
                sql.append(" NOT NULL PRIMARY KEY");
            } else if (item.getAllowNull().compareTo(0) == 0) {
                sql.append(" NOT NULL ");
            } else {
                sql.append(" NULL ");
            }
            sql.append(",");
        }
        sql.deleteCharAt(sql.length() - 1);
        sql.append(")\ntablespace "+ dto.getTableSpace() +";");
        //给表添加说明
        sql.append("COMMENT ON TABLE " + dto.getNewTable() + " IS '" + dto.getTableComment() + "';");
        //给字段添加说明
        for (DbTableFieldModel item : dto.getDbTableFieldList()) {
            sql.append("COMMENT ON COLUMN " + dto.getNewTable() + "." + item.getField() + " IS '" + item.getFieldName() + "';");
        }
        JdbcUtil.custom(dto.getConn(),sql.toString());
    }

    @Override
    public String getDbTime(Connection conn) {
        String time = "";
        StringBuilder sql = new StringBuilder();
        sql.append("select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as TIME ");
        ResultSet result = JdbcUtil.query(conn, sql.toString());
        try {
            while (result.next()) {
                time = result.getString("TIME");
            }
            return time;
        } catch (Exception e) {
            e.getMessage();
        }
        return time;
    }

    @Override
    public String getSqlByStructure(String sql,Connection conn,String table,String tableSpace) {
        /**
         * 说明：一个实例对应一个数据库，多个模式，一个用户对应一个模式，同oracle
         * 表空间需默认：MAIN
         */
        return sql.
                replace(DbSttEnum.TABLE.getTarget(),table).
                replace(DbSttEnum.DB_SCHEMA.getTarget(),DbSttEnum.USER_NAME.getValByConn(conn)).
                replace(DbSttEnum.TABLE_SPACE.getTarget(),tableSpace);
    }


    //---------------------------------dm---------------------------------------------------------------

    /**
     * 数据库备份
     *
     * @param userName
     * @param password
     * @param host
     * @param port
     * @param path
     * @param fileName
     */
    public static String dmBackUp(String userName, String password, String host, String port, String path,
                                  String fileName) {
        try {
            File saveFile = new File(path);
            if (!saveFile.exists()) {
                saveFile.mkdirs();
            }
            StringBuffer dexp = new StringBuffer();
            dexp.append("dexp ");
            dexp.append(userName);
            dexp.append("/");
            dexp.append(password);
            dexp.append("@");
            dexp.append(host);
            dexp.append(":");
            dexp.append(port);
            dexp.append(" file=");
            dexp.append(path + fileName);
            dexp.append(" owner=" + userName);
            Process p = Runtime.getRuntime().exec(dexp.toString());
            @Cleanup BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), Charset.forName("GBK")));
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            br.close();
            p.waitFor();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return path + fileName;
    }

}
